package org.clzps.filetransfer.ftp;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.SocketException;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.clzps.filetransfer.FileTransferHelper;
import org.clzps.filetransfer.common.BasicCommon;
import org.clzps.filetransfer.common.SynchroCommon;

/**
 * ftp操作工具包的主要接口类
 * @author Aries Chou 13/09/2011
 *
 */
public class FtpTransferHelper extends FileTransferHelper{
	private static FtpTransferHelper ftpTransferHelper = null;
	private static FtpConfigInfo ftpConfigInfo = null;
	private static FTPClient ftpClient = null;
	
	private FtpTransferHelper() {
		if(ftpConfigInfo == null)
			ftpConfigInfo = new FtpConfig().getFtpInfo();
		
		if(ftpClient == null)
			ftpClient = new FTPClient();
	}
		
	/**
	 * 验证ftp服务器中dirPath是否存在
	 * @param ftp		FTPClient对象
	 * @param dirPath	目录路径
	 */
	protected void validateDirs(FTPClient ftp, String dirPath) {
		String[] paths = dirPath.split("/");
		try {
			for(int i = 0; i < paths.length; i++) {
				if(!ftp.changeWorkingDirectory(paths[i])){
					ftp.makeDirectory(paths[i]);
				}
				ftp.changeWorkingDirectory(paths[i]);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 获取FtpOperation对象的方法，采用单例实现
	 * @return FtpOperation对象
	 */
	public static FtpTransferHelper getInstance() {
		if(ftpTransferHelper == null) {
			ftpTransferHelper = new FtpTransferHelper();
		}
		
		return ftpTransferHelper;
	}
	
	/**
	 * 将单个输入流上传至Ftp服务器的类似：FtpUpload/2011/01/01/20110101123456.jpg的文件中，即上传单个文件，调用方法如：<br />
	 * &nbsp;&nbsp;uploadFile("FtpUpload", "20110101123456", ".jpg", new FileInputStream("c:/test.sql"))
 	 * @param type			存放目录类别(FileUpload)
 	 * @param storePath		存放目录路径(2011/09/17)
 	 * @param storeFileName	存放的文件名(201109171318820997078.sql)
	 * @param in			上传的输入流
	 * @return				成功返回true，否则返回false   
	 */
	@Override
	public FtpBackInfo uploadFile(String type, String storePath, String storeFileName, String suffix, InputStream in) {
		FtpBackInfo fti = null;
		try {
			int reply;
			ftpClient.connect(ftpConfigInfo.getHostname(), ftpConfigInfo.getPort());
			ftpClient.login(ftpConfigInfo.getUsername(), ftpConfigInfo.getPassword());
			reply = ftpClient.getReplyCode();
			
			if(!FTPReply.isPositiveCompletion(reply)) {
				ftpClient.disconnect();
				logger.error("FTP Server is not Positive Now!");
				return fti;
			}
			
			if(storePath == null || storePath == "") 
				storePath = BasicCommon.getStorePath();
			
			if(storeFileName == null || storeFileName == "")
				storeFileName = SynchroCommon.getFileName(suffix);
			
			validateDirs(ftpClient, type + "/" + storePath);
			
			ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
			ftpClient.storeFile(storeFileName, in);
			
			logger.info("Uploaded!");
			
			in.close();
			ftpClient.logout();
			
			fti = new FtpBackInfo();
			fti.setType(type);
			fti.setDataPath(storePath);
			fti.setStoreFileName(storeFileName);
		} catch (IOException e) {
			logger.error(e.getMessage());
		} finally {
			if(ftpClient.isConnected()) {
				try {
					ftpClient.disconnect();
				} catch (IOException e) {
					logger.warn("When disconnect ftp server, " + e.getMessage());
				}
			}
		}
		return fti;
	}
			
	/**
	 * 下载单个文件至指定的目录，调用方法如：<br />
	 * &nbsp;&nbsp;downloadFile("FtpUpload", "/2011/09/13", "201109131318485261156.jpg", "D:/test");
	 * @param type		存放目录类别
	 * @param path		子目录路径
	 * @param filename	文件名称
	 * @param destDir	下载目标文件夹	
	 * @return	成功返回true，否则返回false
	 */
	@Override
	public boolean downloadFile(String type, String path, String filename, String destDir) {
		boolean success = false;
		FileOutputStream fos = null;
		try {
			ftpClient.connect(ftpConfigInfo.getHostname(), ftpConfigInfo.getPort());
			if(ftpClient.login(ftpConfigInfo.getUsername(), ftpConfigInfo.getPassword())) {
				String ftpFile = type + path + "/" + filename;
				fos = new FileOutputStream(destDir + "/" + filename);
				
				ftpClient.setBufferSize(1024);
				
				if(ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE)) {
					ftpClient.retrieveFile(ftpFile, fos);
					success = true;
				}
			}
		} catch (SocketException e) {
			e.printStackTrace();
			success = false;
		} catch (IOException e) {
			e.printStackTrace();
			success = false;
		} catch (Exception e) {
			e.printStackTrace();
			success = false;
		} finally {
			if(ftpClient.isConnected()) {
				try {
					ftpClient.disconnect();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
		return success;
	}
	
}
